<template>
  <g ref="gEl" :style="{ transform: `translate3d(${dragX}px,${dragY}px,0)` }" :data-x="dragX" :data-y="dragY">
    <g
      :style="{ cursor: selected ? 'move' : 'pointer' }"
      @mousedown="dragStart"
      @contextmenu="pathContextmenu"
      @dblclick="pathDblclick"
    >
      <template v-if="type === PipePathType.pipe">
        <path
          v-for="el in pipeComposeData"
          :key="el.stroke"
          :d="d"
          :stroke="el.stroke"
          stroke-linecap="round"
          stroke-linejoin="round"
          :style="{
            'stroke-width': el.strokeWidth,
            fill: 'none',
          }"
        />
      </template>
      <template v-else>
        <path
          :d="d"
          :stroke="pipePathStyle.outerColor"
          style="fill: none"
          stroke-linecap="round"
          stroke-linejoin="round"
          :style="{
            'stroke-width': pipePathStyle.outerSize,
            cursor: selected ? 'move' : 'pointer',
            'stroke-opacity': pipePathStyle.outerOpacity / 100,
          }"
        />
        <template v-if="showArrow">
          <FlowPath
            v-for="(el, i) in arrowData"
            :key="i"
            :center-x="el.x"
            :center-y="el.y"
            :init-width="arrowWidth"
            :init-height="arrowHeight"
            :index="i"
            :type="FlowPathType.Triangle"
            :scale-factor="1"
            :fill="pipePathStyle.outerColor"
            :rotate="el.rotate"
          />
        </template>
      </template>
      <!-- :class="[{ 'dash-path-floating': isFloating, 'dash-path-reverse': isReverse }, 'floating-speed-' + speed]" -->
      <path
        :d="d"
        :stroke-dasharray="`${pipePathStyle.dottedSize},${pipePathStyle.dottedMargin}`"
        :stroke="pipePathStyle.innerColor"
        style="fill: none; pointer-events: none"
        :style="{ 'stroke-width': pipePathStyle.innerSize, cursor: selected ? 'move' : 'pointer' }"
      >
        <animate
          v-if="isFloating"
          attributeType="XML"
          attributeName="stroke-dashoffset"
          from="200"
          to="0"
          :dur="speedValue[speed]"
          repeatCount="indefinite"
        />
      </path>
    </g>
    <template v-if="selected">
      <rect
        v-for="(el, i) in points"
        :key="i"
        rx="4"
        ry="4"
        fill="#4F80FF"
        :x="el.x - operSize / 2"
        :y="el.y - operSize / 2"
        :width="operSize"
        :height="operSize"
      />
      <rect
        v-for="(el, i) in points"
        :key="i"
        fill="rgba(0,0,0,0)"
        :x="el.x - (operSize + 10) / 2"
        :y="el.y - (operSize + 10) / 2"
        :width="operSize + 10"
        :height="operSize + 10"
        :style="{ cursor: 'nw-resize' }"
        @mousedown="rectDragStart($event, el, i)"
        @contextmenu="rectContextmenu($event, el, i)"
      />
    </template>
    <EditableText
      v-for="el in textData"
      :key="el.id"
      v-bind="textHandlers.getTextPosition(el)"
      v-model:width="el.width"
      v-model:height="el.height"
      v-model:value="el.value"
      v-model:editable="el.editable"
    />
  </g>
</template>
<script lang="ts" setup>
import { inject, ref, onBeforeUnmount, watch, computed } from "vue";
import {
  CompCommon,
  DragMoveOptions,
  ConfigurationInstance,
  CompCommonKey,
  PipePathJSON,
  TextPosition,
  PipePathPoint,
  PipePathType,
  PipePathSpeed,
  Point,
  FlowPathType,
} from "/@/components/types";
import { getAngelByP1P2AndXaxis, getDegToXaxis, isLineIntersectRectangle } from "/@/utils/draw";
import { buildShortUUID } from "/@/utils/uuid";
import { PipeComposeItem, usePipePath } from "./usePipePath";
import { usePipePathText } from "./usePipePathText";
import { SvgHeight, SvgWidth, getApplyCondition } from "/@/components/common";
import { PipePathPanelInfo, PipePathStyle } from "/@/Configuration/AttrPanel/types";
import EditableText from "/@/components/base/EditableText.vue";
import { useDrag } from "/@/hooks/useDrag";
import { SvgInfo, ConfigurationType } from "/@/Configuration/types";
import { Condition, PipePathOriginalProps, PipePathSettableProps } from "/@/Configuration/ConditionPanel/types";
import FlowPath from "../FlowPath/FlowPath.vue";

const props = defineProps<{
  id: string;
  index: number;
  centerX: number;
  centerY: number;
  colors: string[];
  pipeComposeData?: PipeComposeItem[];
  scaleFactor: number;
  type: PipePathType;
}>();
const compCommon = inject(CompCommonKey) as CompCommon<PipePathPanelInfo>;
const isEditor = compCommon.isEditor;
const svgInfo = compCommon.getSvgInfo() as SvgInfo;
//双击自动设置文字
function pathDblclick(e) {
  if (isEditor.value) {
    e.preventDefault();
    e.stopPropagation();
    textHandlers.setTextByPoint({
      x: e.offsetX,
      y: e.offsetY,
    });
  }
}
/**
 * 初始化起始数据
 */
const { innerPipeSize, operSize, pipeSize, points, d, outerOpacity, pipeComposeSize, pipeComposeData } = usePipePath({
  containerHeight: SvgHeight * props.scaleFactor,
  containerWidth: SvgWidth * props.scaleFactor,
  centerX: props.centerX,
  centerY: props.centerY,
  scaleFactor: props.scaleFactor,
});
const pipePathStyle = ref<PipePathStyle>({
  innerColor: props.colors[0],
  innerSize: innerPipeSize.value,
  outerColor: props.colors[1],
  outerSize: props.type === PipePathType.flat ? pipeSize.value : pipeComposeSize.value,
  outerOpacity: outerOpacity * 100,
  dottedSize: props.type === PipePathType.flat ? 2 : 4,
  dottedMargin: props.type === PipePathType.flat ? 5 : 6,
});
watch(
  () => pipePathStyle.value.outerSize,
  (v) => {
    let size = v - 5;
    if (size < 10) {
      size = 10;
    } else if (size > 14) {
      size = 14;
    }
    operSize.value = size;
  },
  {
    immediate: true,
  }
);
watch(
  () => props.scaleFactor,
  (v) => {
    points.forEach((p) => {
      p.x = p._x * v;
      p.y = p._y * v;
    });
  }
);
/**
 * text for part path
 */
const { textData, textHandlers } = usePipePathText({
  points,
  innerPipeSize,
  pipeSize,
});
/**
 * drag rect
 */
const { dragStart: rectDragStart } = useDrag<
  [PipePathPoint, number],
  { tX: number; tY: number; dragMove: (o: DragMoveOptions) => void }
>({
  start(startData) {
    let [targetPoint, i] = startData.args;
    const tX = targetPoint.x;
    const tY = targetPoint.y;
    if (compCommon.connection.isConnect(targetPoint.id)) {
      compCommon.connection.startTogether(targetPoint.id);
    } else {
      //当前点还没绑定设备
      compCommon.draggingPipePathRect = targetPoint;
      selectPath();
    }
    startData.args[0] = targetPoint;
    return {
      tX,
      tY,
      dragMove: getRectDragMove(targetPoint),
    };
  },
  move({ dx, dy, startData, startResult }) {
    const targetPoint = startData.args[0];
    compCommon.connection.moveTogether(targetPoint.id, { dx, dy });
    startResult.dragMove({
      dx,
      dy,
      startData: {
        x: startResult.tX,
        y: startResult.tY,
      },
    });
  },
  end({ startData, startResult }) {
    const targetPoint = startData.args[0];
    compCommon.draggingPipePathRect = null;
    if (compCommon.connectingDevice) {
      //互相建立连接关系
      compCommon.connection.connect(targetPoint.id, compCommon.connectingDevice);
      compCommon.connection.connect(compCommon.connectingDevice.id, {
        id: targetPoint.id,
        type: ConfigurationType.PipePath,
        start() {
          return {
            x: targetPoint.x,
            y: targetPoint.y,
          };
        },
        move: startResult.dragMove,
        extra: compCommon.connectingDevice.extra,
      });
      compCommon.connectingDevice = null;
    } else {
      compCommon.connection.endTogether(targetPoint.id);
    }
  },
});
function getRectDragMove(targetPoint: PipePathPoint) {
  return function dragMove({ x, y, dx, dy, startData }: DragMoveOptions) {
    if (dx !== undefined && dy !== undefined) {
      if (!startData) {
        startData = { x: 0, y: 0 };
      }
      x = dx + startData.x;
      y = dy + startData.y;
    }
    targetPoint.x = x as number;
    targetPoint.y = y as number;
    targetPoint._x = (x as number) / props.scaleFactor;
    targetPoint._y = (y as number) / props.scaleFactor;
    if (targetPoint.overlapId) {
      points.forEach((el) => {
        if (el.overlapId === targetPoint.overlapId) {
          el.x = targetPoint.x;
          el.y = targetPoint.y;
          el._x = targetPoint._x;
          el._y = targetPoint._y;
        }
      });
    }
  };
}
/**
 * drag path 先用g的transform实现，最后mouseup的时候再设置坐标值
 */
const selected = ref(false);
const dragX = ref(0);
const dragY = ref(0);

function pathStart() {
  //路径上所有点连接的设备 一起拖动
  //如果连接的是同一个设备 则只需处理其中一个点
  //obj存放所有连接不同设备的需处理的点
  const obj = {};
  const pointIds: string[] = [];
  points.forEach((el) => {
    const conn = compCommon.connection.getConnect(el.id);
    if (conn && conn.length > 0) {
      obj[conn[0].id] = el;
    }
    pointIds.push(el.id);
    // compCommon.startTogether(el.id);
  });
  //只需处理的点数组
  const dragTogetherPoints: PipePathPoint[] = [];
  for (let i in obj) {
    dragTogetherPoints.push(obj[i]);
  }
  return {
    pointIds,
    dragTogetherPoints,
  };
}

function pathMove(options: DragMoveOptions) {
  dragX.value = options.dx as number;
  dragY.value = options.dy as number;
}

function pathEnd() {
  points.forEach((p) => {
    p.x += dragX.value;
    p.y += dragY.value;
    p._x = p.x / props.scaleFactor;
    p._y = p.y / props.scaleFactor;
  });
  dragX.value = 0;
  dragY.value = 0;
}

function selectPath() {
  selected.value = true;
  compCommon.toggleSelect({
    id: props.id,
    type: ConfigurationType.PipePath,
    selected: selected.value,
    index: props.index,
    unSelect() {
      selected.value = false;
    },
    getPipePathInfo,
  });
}

//do drag path
interface StartResult {
  isDragSelect: boolean;
  pointIds?: string[];
  dragTogetherPoints?: PipePathPoint[];
}
const { dragStart } = useDrag<[], StartResult>({
  unStopPropagation: !isEditor.value,
  element: svgInfo.container,
  start() {
    const result: StartResult = { isDragSelect: false };
    if (isEditor.value) {
      result.isDragSelect = compCommon.multipleSelect.startTogether(props.id);
      if (!result.isDragSelect) {
        const { pointIds, dragTogetherPoints } = pathStart();
        dragTogetherPoints.forEach((el) => {
          compCommon.connection.startTogether(el.id, [...pointIds]);
        });
        result.pointIds = pointIds;
        result.dragTogetherPoints = dragTogetherPoints;
        selectPath();
      }
    }
    return result;
  },
  move({ dx, dy, startResult }) {
    if (isEditor.value) {
      if (startResult.isDragSelect) {
        compCommon.multipleSelect.moveTogether({ dx, dy });
      } else {
        pathMove({ dx, dy });
        (startResult.dragTogetherPoints as PipePathPoint[]).forEach((el) => {
          compCommon.connection.moveTogether(el.id, { dx, dy }, [...(startResult.pointIds as string[])]);
        });
      }
    }
  },
  end({ isClick, startResult }) {
    if (isEditor.value) {
      if (startResult.isDragSelect) {
        compCommon.multipleSelect.endTogether();
      } else {
        pathEnd();
        (startResult.dragTogetherPoints as PipePathPoint[]).forEach((el) => {
          compCommon.connection.endTogether(el.id, [...(startResult.pointIds as string[])]);
        });
      }
      if (isClick && startResult.isDragSelect) {
        //点击事件
        selectPath();
      }
    }
  },
});
/**
 * 删除路径
 */
onBeforeUnmount(() => {
  if (selected.value) {
    selected.value = false;
    compCommon.toggleSelect({
      type: ConfigurationType.PipePath,
      selected: false,
      index: props.index,
    });
  }
  //解除所有节点的连接关系
  points.forEach((p) => {
    compCommon.connection.disConnect(p.id);
  });
});
//增加子路径
function addSubPath(targetPoint: PipePathPoint, i: number, isReverse?: boolean) {
  const lastPoint = points[i - 1];
  const nextPoint = points[i + 1];
  const nearPoint = i === points.length - 1 ? lastPoint : nextPoint;
  let newPoint: PipePathPoint = {
    x: targetPoint.x + (nearPoint.x > targetPoint.x ? -50 : 50),
    y: targetPoint.y,
    _x: targetPoint._x,
    _y: targetPoint._y,
    id: buildShortUUID(),
  };
  //目标点是反向路径上的点
  if (targetPoint.isReverse) {
    //反向路径的父子点
    if (targetPoint.isParentNode) {
      if (isReverse) {
        addNewBranch(targetPoint, newPoint, !isReverse);
      } else {
        newPoint.isReverse = true;
        newPoint.isParentNode = true;
        targetPoint.isParentNode = false;
        points.splice(i, 0, newPoint);
      }
    } else {
      addNewBranch(targetPoint, newPoint, isReverse);
    }
  } else {
    if (i === 0 || i === points.length - 1 || nextPoint.isParentNode) {
      if (isReverse) {
        addNewBranch(targetPoint, newPoint, i === points.length - 1);
      } else {
        if (i === points.length - 1) {
          points.push(newPoint);
        } else if (i === 0) {
          points.unshift(newPoint);
        } else {
          points.splice(i + 1, 0, newPoint);
        }
      }
    } else {
      addNewBranch(targetPoint, newPoint, isReverse);
    }
  }
}
//增加新分支路径
function addNewBranch(targetPoint: PipePathPoint, newPoint: PipePathPoint, isReverse?: boolean) {
  let p1: PipePathPoint, p2: PipePathPoint;
  const pNode: PipePathPoint = {
    x: targetPoint.x,
    y: targetPoint.y,
    _x: targetPoint._x,
    _y: targetPoint._y,
    isParentNode: true,
    overlapId: targetPoint.overlapId || (targetPoint.overlapId = buildShortUUID()),
    id: buildShortUUID(),
  };
  if (isReverse) {
    newPoint.isParentNode = true;
    pNode.isParentNode = false;
    newPoint.isReverse = true;
    pNode.isReverse = true;
    p1 = newPoint;
    p2 = pNode;
  } else {
    //先push一个父节点，再push新节点
    p1 = pNode;
    p2 = newPoint;
  }
  points.push(p1);
  points.push(p2);
}
//根据父节点索引，删除父节点，并递归删除所有后代节点
function delParentNodeByIndex(parentNodeIndex: number) {
  let delNum = 1;
  let j = parentNodeIndex + 1;
  let p = points[j];
  while (p && !p.isParentNode) {
    if (p.overlapId) {
      for (let k = 0; k < points.length; k++) {
        let node = points[k];
        if (node.overlapId === p.overlapId && k !== j && node.isParentNode) {
          delParentNodeByIndex(k);
          //删除后索引有变化 必须从新开始遍历
          k = 0;
        }
      }
    }
    //删除绑定的文字
    textHandlers.delTextByIndex(j);
    delNum++;
    p = points[++j];
  }
  points.splice(parentNodeIndex, delNum);
}
/**
 * 垂直或水平对齐
 */
function align() {
  points.forEach((p, i) => {
    const nextP = points[i + 1];
    if (nextP && !nextP.isParentNode) {
      const xDeg = getDegToXaxis(p, nextP);
      const oX = nextP.x;
      const oY = nextP.y;
      if (xDeg <= 45) {
        nextP.y = p.y;
        nextP._y = p._y;
      } else {
        nextP.x = p.x;
        nextP._x = p._x;
      }
      if (nextP.overlapId) {
        points.forEach((p) => {
          if (p.overlapId === nextP.overlapId) {
            p.x = nextP.x;
            p._x = nextP._x;
            p.y = nextP.y;
            p._y = nextP._y;
          }
        });
      }
      if (compCommon.connection.isConnect(nextP.id)) {
        compCommon.connection.startTogether(nextP.id);
        compCommon.connection.moveTogether(nextP.id, { dx: nextP.x - oX, dy: nextP.y - oY });
        compCommon.connection.endTogether(nextP.id);
      }
    }
  });
}
/**
 * 右键rect弹出菜单
 */
function rectContextmenu(e: MouseEvent, p: PipePathPoint, i: number) {
  const isDelPath = points.length === 2;
  const menuItems = [
    {
      name: "增加子路径",
      handler() {
        addSubPath(p, i);
      },
    },
    {
      name: "增加反向子路径",
      handler() {
        addSubPath(p, i, true);
      },
    },
    {
      name: isDelPath ? "删除路径" : "删除当前节点",
      handler() {
        if (isDelPath) {
          compCommon.deleteCompItem(props.id);
        } else {
          if (p.isParentNode) {
            delParentNodeByIndex(i);
          } else {
            if (i > 0 && points[i - 1].isParentNode && (i === points.length - 1 || points[i + 1].isParentNode)) {
              delParentNodeByIndex(i - 1);
            } else {
              textHandlers.delTextByIndex(i);
              points.splice(i, 1);
            }
          }
        }
      },
    },
  ];
  if (compCommon.connection.isConnect(p.id)) {
    menuItems.push({
      name: "解除连接",
      handler() {
        compCommon.connection.disConnect(p.id);
      },
    });
  }
  compCommon.showContextmenu(e, { data: menuItems });
}
//在距离用户点击的位置最近的路径段的中间插入节点
function insertPoint(clickPoint: Point) {
  const index = textHandlers.findPartPathByPoint(clickPoint);
  const p1 = points[index];
  const p2 = points[index + 1];
  const centerPoint: PipePathPoint = {
    x: (p1.x + p2.x) / 2,
    y: (p1.y + p2.y) / 2,
    _x: (p1._x + p2._x) / 2,
    _y: (p1._y + p2._y) / 2,
    isReverse: p1.isReverse,
    id: buildShortUUID(),
  };
  points.splice(index + 1, 0, centerPoint);
  selectPath();
}
/**
 * 右键路径弹出菜单
 */
const isFloating = ref(false);
const isReverse = ref(false);
const gEl = ref<SVGGElement>();
function pathContextmenu(e: MouseEvent) {
  const menuItems = [
    {
      name: "设置文字",
      handler() {
        textHandlers.setTextByPoint({
          x: e.offsetX,
          y: e.offsetY,
        });
      },
    },
    {
      name: "插入节点",
      handler() {
        insertPoint({
          x: e.offsetX,
          y: e.offsetY,
        });
      },
    },
    {
      name: "流动",
      children: [
        {
          name: isFloating.value ? "停止" : "开始",
          handler() {
            isFloating.value = !isFloating.value;
          },
        },
      ],
    },
    {
      name: "对齐",
      handler() {
        align();
      },
    },
    {
      name: showArrow.value ? "隐藏箭头" : "显示箭头",
      handler() {
        showArrow.value = !showArrow.value;
      },
    },
  ];
  const textRef = textHandlers.getTextRefByPoint({
    x: e.offsetX,
    y: e.offsetY,
  });
  if (textRef) {
    menuItems.splice(2, 0, {
      name: "文字方向",
      children: [
        {
          name: "上",
          handler() {
            textRef.position = TextPosition.Top;
          },
        },
        {
          name: "下",
          handler() {
            textRef.position = TextPosition.Bottom;
          },
        },
      ],
    });
  }
  compCommon.showContextmenu(e, { data: menuItems, id: props.id, element: gEl.value as SVGGElement });
}
function setPipePathStyle(style: PipePathStyle) {
  pipePathStyle.value = style;
  if (style.outerSize) {
    pipeComposeSize.value = style.outerSize;
  }
}
function getPipePathInfo(): PipePathPanelInfo {
  return {
    points: points,
    isFloating: isFloating.value,
    isReverse: isReverse.value,
    pipePathStyle: pipePathStyle.value,
    speed: speed.value,
    type: props.type,
    setFloating(f) {
      isFloating.value = f;
    },
    setReverse(r) {
      isReverse.value = r;
    },
    setStyle: setPipePathStyle,
    setSpeed(val) {
      speed.value = val;
    },
  };
}
watch([points, isFloating, isReverse], () => {
  compCommon.updatePanelInfo({
    type: ConfigurationType.PipePath,
    panelInfo: getPipePathInfo(),
  });
});
const showArrow = ref(true);
const arrowWidth = 14;
const arrowHeight = 14;
const arrowData = computed(() => {
  const data: (Point & { rotate: number })[] = [];
  points.forEach((p, i) => {
    const nextP = points[i + 1];
    if (nextP && !nextP.isParentNode) {
      data.push({
        x: (p.x + nextP.x) / 2,
        y: (p.y + nextP.y) / 2,
        rotate: getAngelByP1P2AndXaxis(p, nextP),
      });
    }
  });
  return data;
});

/**
 * expose
 */
const speed = ref<PipePathSpeed>(PipePathSpeed.normal);
const speedValue: { [key: string]: string } = {
  [PipePathSpeed.slow]: "7s",
  [PipePathSpeed.normal]: "5s",
  [PipePathSpeed.middle]: "3s",
  [PipePathSpeed.fast]: "1.5s",
};
const conditionData = ref<Condition[]>([]);
let originalProps: PipePathOriginalProps | null = null;
function getOriginalProps() {
  if (!originalProps) {
    return {
      isReverse: isReverse.value,
      isFloating: isFloating.value,
      speed: speed.value,
      pipePathStyle: pipePathStyle.value,
      type: props.type,
    };
  }
  return originalProps;
}
function previewCondition(condition: Partial<Condition>) {
  if (!originalProps) {
    originalProps = getOriginalProps();
  }
  condition.isReverse !== undefined && (isReverse.value = condition.isReverse);
  condition.isFloating !== undefined && (isFloating.value = condition.isFloating);
  condition.speed !== undefined && (speed.value = condition.speed);
  condition.pipePathStyle !== undefined && setPipePathStyle(condition.pipePathStyle);
}
function restoreCondition() {
  if (originalProps) {
    isReverse.value = originalProps.isReverse;
    isFloating.value = originalProps.isFloating;
    speed.value = originalProps.speed;
    setPipePathStyle(originalProps.pipePathStyle);
    originalProps = null;
  }
}
const myExpose: ConfigurationInstance<PipePathJSON, PipePathOriginalProps> = {
  isInBoxSelect(boxSelect) {
    for (let i = 0; i < points.length - 1; i++) {
      const p1 = points[i];
      const p2 = points[i + 1];
      if (
        isLineIntersectRectangle(
          p1.x,
          p1.y,
          p2.x,
          p2.y,
          boxSelect.x,
          boxSelect.y,
          boxSelect.x + boxSelect.width,
          boxSelect.y + boxSelect.height
        )
      ) {
        return true;
      }
    }
    return false;
  },
  select() {
    selected.value = true;
    compCommon.toggleSelect({
      type: ConfigurationType.PipePath,
      selected: selected.value,
      index: props.index,
      unSelect() {
        selected.value = false;
      },
      multiple: true,
      id: props.id,
      drag: {
        start: pathStart,
        move: pathMove,
        end: pathEnd,
      },
      getPipePathInfo,
    });
  },
  toJSON() {
    const _textData = textData.value.map((el) => ({
      ...el,
      initValue: el.value,
    }));
    return {
      id: props.id,
      points: points.map((p) => Object.assign({}, p, { x: p._x, y: p._y })),
      textData: _textData,
      colors: props.colors || [],
      isFloating: isFloating.value,
      isReverse: isReverse.value,
      style: pipePathStyle.value,
      type: props.type,
      conditionData: conditionData.value,
      speed: speed.value,
      showArrow: showArrow.value,
    };
  },
  setJSON(data) {
    points.splice(0, points.length, ...data.points);
    textData.value = data.textData;
    isFloating.value = data.isFloating;
    isReverse.value = data.isReverse;
    pipePathStyle.value = data.style;
    if (data.style.outerSize) {
      pipeComposeSize.value = data.style.outerSize;
    }
    conditionData.value = data.conditionData || [];
    speed.value = data.speed || PipePathSpeed.normal;
    showArrow.value = data.showArrow === undefined ? true : data.showArrow;
  },
  setConnection(drag, subId) {
    const targetPoint = points.find((el) => el.id === subId.id);
    if (targetPoint) {
      drag.extra = {
        connectPositionIndex: subId.position,
      };
      //互相建立连接关系
      compCommon.connection.connect(targetPoint.id, drag);
      compCommon.connection.connect(drag.id, {
        id: targetPoint.id,
        type: ConfigurationType.PipePath,
        start() {
          return {
            x: targetPoint.x,
            y: targetPoint.y,
          };
        },
        move: getRectDragMove(targetPoint),
        extra: drag.extra,
      });
      return true;
    }
    return false;
  },
  handleData(data) {
    restoreCondition();
    const applyCondition = getApplyCondition(conditionData.value, data);
    if (applyCondition.length > 0) {
      applyCondition.forEach((el) => {
        previewCondition(el);
      });
    }
  },
  getConditionData() {
    return conditionData.value;
  },
  setConditionData(data) {
    conditionData.value = data;
  },
  previewCondition,
  restoreCondition,
  getDisplayInfo() {
    return {
      name: "管道",
    };
  },
  getOriginalProps,
  getBox() {
    let minX = points[0].x,
      minY = points[0].y,
      maxX = points[0].x,
      maxY = points[0].y;
    points.forEach((p) => {
      if (minX === undefined || p.x < minX) {
        minX = p.x;
      }
      if (minY === undefined || p.y < minY) {
        minY = p.y;
      }
      if (maxX === undefined || p.x > maxX) {
        maxX = p.x;
      }
      if (maxY === undefined || p.y > maxY) {
        maxY = p.y;
      }
    });
    return {
      x: minX,
      y: minY,
      width: maxX - minX,
      height: maxY - minY,
      maxX,
      maxY,
    };
  },
  translate(dx, dy) {
    points.forEach((el) => {
      el.x = el.x + dx;
      el.y = el.y + dy;
      el._x = el.x / props.scaleFactor;
      el._y = el.y / props.scaleFactor;
    });
  },
};
defineExpose(myExpose);
</script>
<style>
/* .dash-path {
  stroke-dashoffset: 200;
}
.dash-path-reverse {
  stroke-dashoffset: -200;
}
.dash-path-floating {
  animation: dash 5s linear infinite;
}
.floating-speed-0 {
  animation-duration: 7s;
}
.floating-speed-1 {
  animation-duration: 5s;
}
.floating-speed-2 {
  animation-duration: 3s;
}
.floating-speed-3 {
  animation-duration: 1.5s;
}
@keyframes dash {
  to {
    stroke-dashoffset: 0;
  }
} */
</style>
